Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

Normative: Switch syntax to ??. #48

Closed
wants to merge 1 commit into from
Closed

Normative: Switch syntax to ??. #48

wants to merge 1 commit into from

Conversation

littledan
Copy link
Member

Follows the conclusion of the discussion at
#34

@madskonradsen
Copy link

That calls for a celebration! :)

README.md Outdated
obj?.prop // optional static property access
obj?.[expr] // optional dynamic property access
func?.(...args) // optional function or method call
obj??.prop // optional static property access
Copy link

@FranklinYu FranklinYu Feb 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Align comments?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed alignment.

@Mouvedia
Copy link

Mouvedia commented Feb 24, 2018

By "conclusion" he meant that this comment has a lot of upvotes. There's nothing official about it and there are other comments with even more 👍 .

@littledan
Copy link
Member Author

@Mouvedia Something that's somewhat official about it is that the plan to switch to ?? was presented to TC39 in January 2018 with some discussion but overall a relatively supportive committee.

@littledan
Copy link
Member Author

Note that there is a parallel change for nullish coalescing at tc39/proposal-nullish-coalescing#23 (to use ??: syntax).

@hax
Copy link
Member

hax commented Feb 26, 2018

Too many ?... and ??. looks too close to ??: which very harmful to readability...

const city = staff??.company??.address??.city??:defaultCity;

PS. Compare to my syntax suggestion:

const city = staff!.company!.address!.country??defaultCity;

@alangpierce
Copy link

alangpierce commented Feb 26, 2018

@hax Nullish coalescing is a binary operator, so it normally would be written with spaces:

const city = staff??.company??.address??.city ??: defaultCity;

I think the spacing makes it reasonable to distinguish the operators from each other. As you mentioned in your original comment (#34 (comment)), !. conflicts with TypeScript, which seems really concerning to me, even if there are migration paths. My impression is that #34 is still the best place to discuss syntax alternatives, and this PR discussion is best focused on the PR itself and whether it follows from previous discussions.

My reading of #34 is that the four operators in this PR have by far the most support. See #34 (comment) and the comments immediately above and below it for a poll of various alternatives. (And, as mentioned, TC39 seems to be mostly in favor of this syntax, and they're the ones actually making the decision.) Hopefully most people are at least agreed that this is an improvement over the original ?., ?.[, ?.(, which is what this PR is replacing.

@lehni
Copy link

lehni commented Feb 26, 2018

Even with spaces, I still prefer @hax's syntax suggestion, and agree that the similarity between the two operators is rather confusing and doesn't help quick reading / understanding of code. This just looks much more readable to me:

const city = staff!.company!.address!.country ?? defaultCity;

And so does this:

const city = staff?.company?.address?.country ?? defaultCity;

@claudepache
Copy link
Collaborator

@hax, @lehni Discussion about the syntax must go in #34, not here. (But please do not repeat arguments you’ve already done.)

@littledan
Copy link
Member Author

@claudepache What do you think of this PR?

@claudepache
Copy link
Collaborator

@littledan

What do you think of this PR?

I haven’t had time to review it yet. But yes, I'm favourable to switch to that syntax, on condition that the syntax of nullish-coalescing is also changed (tc39/proposal-nullish-coalescing#23 or anything else).

@hax
Copy link
Member

hax commented Feb 26, 2018

@alangpierce Coding style can help, but these too close symbols also restrict the options of coding style. For example, you can not also add spaces around ??. for any reason:

staff??.company_name??.very_long_address??.#private_field // not very clear
staff ??. company_name ??. very_long_address ??. #private_field // better
staff ??. company_name ??. very_long_address ??. #private_field ??: default_value // unfortunate...

Try two spaces...

staff ??. company_name ??. very_long_address ??. #private_field  ??:  default_value 

Maybe we need three?

staff ??. company_name ??. very_long_address ??. #private_field   ??:   default_value

...So, see the problem?

Note, I just use !. for comparison because I believe it's the best option, but ?& also better than current combination in readability. Eg.

staff ?&. company_name ?&. very_long_address ?&. #private_field ?? default_value

And ?> (though it may have other problems)

staff ?>. company_name ?>. very_long_address ?>. #private_field ?? default_value

My reading of #34 is that the four operators in this PR have by far the most support.

Unfortunately the supporters all ignore the readability problem of ??. with ??:.

My impression is that #34 is still the best place to discuss syntax alternatives

The thread is already too long to catch. So maybe we should create a new issue.

Follows the conclusion of the discussion at
#34
@Tiedye
Copy link

Tiedye commented Mar 7, 2018

What conclusion #51 ?

Copy link
Collaborator

@claudepache claudepache left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some corrections.

Also, given the strong resistance against that syntax, we should probably wait that TC39 confirms whether it is the way to go.

* In order to allow `foo?.3:0` to be parsed as `foo ? .3 : 0` (as required for backward compatibility), a simple lookahead is added at the level of the lexical grammar, so that the sequence of characters `?.` is not interpreted as a single token in that situation (the `?.` token must not be immediately followed by a decimal digit).
### Why two question marks instead of one?

An earlier version of this proposal used `??.` for the optional chaining operator, with `??[` for dynamic property access and `??(` for optional function/method calls. The switch to two question marks allows for more consistency and the ability to omit the surprising `.` in the latter two cases. See [the past discussion](https://github.com/tc39/proposal-optional-chaining/issues/34) on this topic for more details.
Copy link
Collaborator

@claudepache claudepache Mar 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too zealous search-and-replace? Replace back ??. / ??[/??( with?. / ?.[ / ?.( in that sentence.

* constructor or template literals in/after an Optional Chain: `new a?.b()`, ``a?.b`{c}` ``
* optional construction: `new a??()`
* optional template literal: ``a??`{b}` ``
* constructor or template literals in/after an Optional Chain: `new a??b()`, ``a??.b`{c}` ``
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new a??.b()

@@ -165,28 +166,13 @@ All the above cases will be forbidden by the grammar or by static semantics so t
<dl>


<dt>obj?.[expr] and func?.(arg) look ugly. Why not use obj?[expr] and func?(arg) as does &lt;language X>?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of deleting that FAQ item, let’s replace it with:

obj??.prop, obj??[expr] and func??(arg) look like null coalescing in <language X>. Why not use obj?.prop, obj?[expr] and func?(arg) as does <language X>?

Further adaptations below.


<dd>

We don’t use the `obj?[expr]` and `func?(arg)` syntax, because of the difficulty for the parser to efficiently distinguish those forms from the conditional operator, e.g., `obj?[expr].filter(fun):0` and `func?(x - 2) + 3 :1`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let’s be more affirmative: ”We can’t use...”


We don’t use the `obj?[expr]` and `func?(arg)` syntax, because of the difficulty for the parser to efficiently distinguish those forms from the conditional operator, e.g., `obj?[expr].filter(fun):0` and `func?(x - 2) + 3 :1`.

Alternative syntaxes for those two cases each have their own flaws; and deciding which one looks the least bad is mostly a question of personal taste. Here is how we made our choice:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a temporary measure, replace with: ”[TODO: explain the rationale and the tradeoffs behind the choice of ??]” (and delete the two bullets just below).

@@ -22,7 +22,7 @@
<h1>Scope</h1>
<p>This is the spec text of the <a href="https://github.com/tc39/proposal-optional-chaining/">Optional Chaining proposal</a> in ECMAScript. </p>

<p>For the syntax, we use the `?.` token, with a lookahead at the level of the lexical grammar that allows to discriminate between `a?.b` (optional chaining) and `a?.3:0` (conditional operator, whose meaning cannot be changed due to backward compatibility constraints).</p>
<p>For the syntax, we use the `??.` token. An earlier version of this proposal used `?.`</p>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, we use three tokens, namely ??., ??[ and ??(. I propose (don’t hesitate to improve the text):

For the syntax, we use the ?? sequence of characters for suggesting ”optional”. An earlier version of this proposal used the ?. token for that purpose.


RightBracePunctuator ::
`}`
`??.` `??(` `??[`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be surrounded by <ins>.

OptionalChainingPunctuator Arguments[?Yield, ?Await]
`??[` Expression[+In, ?Yield, ?Await] `]`
`??.` IdentifierName
`??(` ArgumentsList[?Yield, ?Await] `,`? `)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You missed ??(); that is to say, ArgumentsList is optional, but the optional comma is forbidden if ArgumentsList is omitted:

  `??(`  `)`
  `??(` ArgumentList[?Yield, ?Await] `,`? `)`

OptionalChain :
`??(` ArgumentsList? `)`
</emu-grammar>
<emu-grammar>OptionalChain : `??(` ArgumentsList `,` `)` </emu-grammar>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’d say (as above):

  <emu-grammar>
    OptionalChain :
      `??(` `)`
      `??(` ArgumentList[?Yield, ?Await] `,`? `)`
   </emu-grammar>

@@ -652,7 +642,7 @@ <h1>Expression Rules</h1>
</emu-alg>
<emu-grammar>
OptionalChain :
OptionalChainingPunctuator Arguments
`??(` ArgumentsList `,`? `)`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above.

    OptionalChain :
      `??(` `)`
      `??(` ArgumentsList `,`? `)`
      OptionalChain Arguments

@claudepache claudepache mentioned this pull request Mar 12, 2018
@jrista
Copy link

jrista commented Mar 13, 2018

Are we seriously considering ??. and ??: as better than ?. and ?? for his proposal? I don't know where anyone is seeing a consensus that ??. is more desired or accepted than ?. by the community at large. In fact, it seems that ?. is far more accepted based on #51. I find ??. to be very heavy and unsightly, and in all honesty don't really want to be writing code littered with this verbose operator...

@gisenberg
Copy link
Member

@jrista Please use #34 for feedback related to syntax.

@jrista
Copy link

jrista commented Mar 13, 2018

I've commented in the other thread, but I have to say, this PR and the direction this proposal is now taking is very, very concerning. Ergonomics, understandability, verbosity. We are starting to head in the wrong direction on all fronts, and I truly hope this PR does not get merged.

@claudepache
Copy link
Collaborator

@littledan If you still think that this PR should be merged, could you apply the requested changes?

@jrista
Copy link

jrista commented Mar 30, 2018

I don't know that the debate over the operator has been settled. At this time, it still appears as though, despite it's supposed inconsistency, ?./?? is still by far the more preferred operator. Discussions on the operators seem to have stalled, but I don't believe that means the debate has ended, nor that ??. is what we should be using.

@gisenberg
Copy link
Member

I presented both options to the committee last week and strongly advocated for the current syntax, calling out the strong community support. Both proposals had hard vetoes that prevented stage advancement:

  • ?. because of inconsistency and overloading the meaning of . for bracket/method access.
  • ??. because of the impact to the token for the null coalescing operator.

Paring back the proposal to only support ?. and opt-out of bracket and method access also received strong opposition. The absence of symmetry between member and bracket access and the choice of token ruling out future extensions to optional method/bracket access were cited as reasons that would block advancement of only ?..

There was no strong opposition to ??. ??( ??[ assuming null coalescing could find a better token (eg: not ??:). ??? and ||| were floated as possible alternatives.

Looking at the poll results for possible token options, there are really only two options and we've definitively ruled out one. I suspect that hard constraints settle the syntax debate, but I'm open to alternatives.

@claudepache claudepache mentioned this pull request Mar 31, 2018
@rattrayalex
Copy link

Is there a good place for discussion? Eg; I am curious what made ??: unacceptable. I assume this PR chain would not be the best place for follow-up questions and alternate suggestions, however.

@littledan
Copy link
Member Author

@rattrayalex Some people didn't like the colon. Not sure what more there is to say; I guess it makes it less analogous to ||.

@rattrayalex
Copy link

Cool, thanks @littledan. Perhaps they could be persuaded (much of es syntax design seems very constraint-driven). I assume you're working with the fine folks over at optional chaining. May be worth opening an informal bikeshed poll over on the other repo.

@selipso
Copy link

selipso commented Nov 30, 2018

IMO null coalescing should be ||| as it's the only one that makes intuitive sense and leaves open the possibility to an &&& operator where 0 and the empty string are considered truthy.

That would also open up ?? to optional chaining without having that pesky . for square bracket notation.

@ljharb
Copy link
Member

ljharb commented Nov 30, 2018

@selipso in the TC39 meeting this week it was brought up that if === is a stricter ==, then ||| would be a stricter ||, and since || deals with truthiness, ||| would need to deal with true - a compelling argument that seemed to convince many people that ||| is not an option for this proposal.

@selipso
Copy link

selipso commented Dec 1, 2018

Then by that logic ||| is 'stricter' than || because nullish types are more limiting than the loosey-goosey || where !(0 || '') === true. Perfectly intuitive to me and easily explainable to even my high school students that I teach programming to.

Since we have only one point of reference for this syntax (== vs ===) I don't think 'stricter' is the right word for it but rather a "restriction of scope" in the underlying values comparison. We are essentially restricting scope by adding a third character in both cases.

With == vs === we are restricting scope to exact matches of the underlying data type. With || vs ||| we are restricting scope from "falsy" values to only null and undefined values.

@hax
Copy link
Member

hax commented Dec 1, 2018

@selipso I think we should learn from failure of visually too close operators. The mainstream coding style now only allow === and forbidden == to avoid the confusion and accidently typos, there is also a rule which forbidden | and & to avoid potential confusion/typo with || and &&, so it's hard to convince the community adding ||| (and adding &&& for consistency) would be a good idea.

Note we can forbidden == because all == use cases could be converted to === with explicit type cast. We can forbidden & and | because most modules do not need bitwise operations, and we can choose to opt in if we really need bitwise ops in special modules. But we can't forbidden || because it's very correct to use || as logical operator, both || and ||| have very common use cases. This is why we need null coalescing operator, and I think as the motivation of some linter rules suggest, we'd better use syntax which have enough distance to avoid the confusion and typo.

@selipso
Copy link

selipso commented Dec 1, 2018

@hax I, for one, would be fine with || being “less recommended” compared to |||. The concept of ‘falsy’ is a sticking point in JavaScript for both new and experienced programmers alike (esp. coming from C). I still see codebases with both == and === used cleverly and also appropriately. It will never be forbidden to use older syntax, but when some operator does something very similar to another operator, there is no need to add a mental switching cost with a different control character.

This would also free up optional chaining (which IMO is a more exciting and practical language feature) to use either ?. or ??., or even both! Makes everyone happy.

@jrista
Copy link

jrista commented Dec 7, 2018

@hax There are definitely valid current uses of ==, and not all == should nor could be converted to === and still maintain the desired functionality. I commonly use variable == null to do null or undefined checks rather than falsy checks, for example.

@hax
Copy link
Member

hax commented Dec 10, 2018

@jrista No. All valid use cases of == can be replaced by === and get the better clearance and readability.

But variable == null is ok, even it could be replaced by variable === undefined || variable === null. It's very common we don't care about the difference between null/undefined, yes I myself also use x == null. But in all other cases, we should use === in engineering. (Note, it always ok to ignore all coding style if you are writing toy project or one-time script. But I'm assuming we are discussing professional programming which your codebase would be long-live and involve team collaboration.)

@jrista
Copy link

jrista commented Jan 2, 2019

@hax It may be that you can, one way or another, find a way to eliminate ALL == and replace them with ===. Is that always the best way? It can needlessly increase the verbosity of code...and depending on the project and the nature of the data it may be very common to need to do null/undefined checks, and pounding out the full variable === null || variable === undefined quickly becomes tedious and mind numbing.

I find value in == in some cases, though, beyond just the variable == null case. Another valid example, IMO, is when you are working with "dirty data", which sometimes occurs with existing APIs. I've had to write code over the years that needs to work with APIs that are not properly versioned in a detectable way, for which multiple versions may be deployed and used and poor version management coupled with unexpected API deployments can wreak havoc, and where certain data such as numbers may be quoted or not, and where magic numbers are often used (ugh, old APIs...). For example 0 == '0' can be quite useful, since the data may be '0' or 0 depending on the API version.

I guess I try to be pragmatic rather than dogmatic when it comes to which operator to use. When I use ==, I ALWAYS comment in the code as to why, though, as there have been times when I've worked with more dogmatic developers who will happily convert every == they see it to === without considering the implications. ;) As often ends up being the case, I am able to introduce a little bit of pragmatism into those dogmatic individuals and simplify their lives a little bit once they learn how useful == can be in these special cases. ;D (And yes, I would consider them special cases...special, and completely valid.)

@hax
Copy link
Member

hax commented Jan 3, 2019

I ALWAYS comment in the code as to why

If you add comments for every == usage, it's definitely ok to use == 😂 But why not just write a === Number(b) to make your intention explicitly? IMO, comments are always last resort. If we can make the code self-describing, we'd better write code instead of comments.

though, as there have been times when I've worked with more dogmatic developers

You may think me (and many) as "dogmatic", we can argue it in other place (we already offtopic in this issue) but that's the real problem in collaboration. In a big team, you have to consider the cost of communication.

@jrista
Copy link

jrista commented Jan 3, 2019

@hax: I would not simply do a === Number(b) either, not without a comment, as I have also had other developers come along and change that to just a === b, seeing only one form of the data, thinking the Number(b) was unnecessary. 🤷‍♂️

The "cost" of communication is not very large when it is a comment right in the code, right where it needs to be.

@ljharb
Copy link
Member

ljharb commented Jan 3, 2019

A developer who would think it’s safe to casually remove an explicit type coercion likely would also casually remove a comment, believing it to be irrelevant :-)

@0rvar
Copy link

0rvar commented Mar 29, 2019

I do not like the change to ??. at all. I fail to see what the improvement is over ?., and it is much more verbose.

@MatthiasKunnen
Copy link

@0rvar, I believe it was already decided to seek stage advancement with the current spec. The current spec uses ?.
It is my understanding that this pr will not be merged. After stage 2 is reached this repository will undergo some cleaning and PRs and issues will be closed.

This is a summary of issues I've read over the months.

@littledan
Copy link
Member Author

I think many of us are leaning more towards ?. these days, so I'm closing this PR for clarity. We can reopen it if we see a need to revisit it later.

@littledan littledan closed this Apr 5, 2019
@claudepache claudepache added the alternative syntax past ideas and discussions about alternative syntaxes label Jun 9, 2019
@ljharb ljharb deleted the qq branch January 24, 2022 21:12
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
alternative syntax past ideas and discussions about alternative syntaxes
Projects
None yet
Development

Successfully merging this pull request may close these issues.